/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.common.base.mapper.query;

import com.alibaba.fastjson2.*;
import com.je.common.base.entity.func.FuncQueryStrategy;
import com.je.common.base.func.funcPerm.FuncDataPermVo;
import com.je.common.base.service.QueryBuilderService;
import com.je.common.base.spring.SpringContextHolder;
import com.je.ibatis.extension.conditions.ConditionsWrapper;
import org.apache.commons.lang.StringUtils;

import java.io.Serializable;
import java.sql.Array;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Query
 *
 * @author wangmm@ketr.com.cn
 * @date 2019/12/9
 */
public class Query implements Serializable {

    private static final long serialVersionUID = 1L;

    //----------------------- 用户输入条件
    /**
     * 左侧字典查询条件
     */
    private List<Condition> tree = new ArrayList<>();
    /**
     * 模糊查询条件
     */
    private List<Condition> quick = new ArrayList<>();
    /**
     * 高级查询条件
     */
    private List<Condition> group = new ArrayList<>();
    /**
     * 标记查询条件
     */
    private List<Condition> mark = new ArrayList<>();
    /**
     * 表格列查询条件
     */
    private List<Condition> column = new ArrayList<>();
    /**
     * 流程查询条件
     */
    private List<Condition> workflow = new ArrayList<>();
    /**
     * 排序
     */
    private List<Order> order = new ArrayList<>();
    /**
     * js自定义条件
     */
    private List<Condition> custom = new ArrayList<>();


    //----------------------- app相关
    /**
     * appId
     */
    private String appId = "";
    /**
     * app功能配置
     */
    private JSONObject appFunc = new JSONObject();

    //----------------------- 子功能查询选择条件
    /**
     * 子功能或查询选需要用到的字段值
     */
    private JSONObject formData = new JSONObject();

    //----------------------- 查询策略
    /**
     * 查询策略ID
     */
    private String strategyId = "";

    /**
     * 查询策略实体
     */
    private FuncQueryStrategy strategyBean;
    /**
     * 查询策略条件
     */
    private List<Condition> strategy = new ArrayList<>();

    //----------------------- 功能配置条件
    /**
     * funcId
     */
    private String funcId = "";
    /**
     * funcPkCode
     */
    private String funcPkCode = "";
    /**
     * 覆盖功能whereSql，默认false
     */
    private boolean overrideFuncWhere = false;

    /**
     * 覆盖功能funcOrderSql，默认false
     */
    private boolean overrideFuncOrder = false;
    /**
     * whereSql
     */
    private String funcWhereSql = "";
    /**
     * orderSql
     */
    private String funcOrderSql = "";

    //----------------------- 功能数据权限

    //----------------------- 功能数据权限
    /**
     * applySql  兼容使用  不得以 AND 开头
     */
    private String applySql = "";

    private String syProductId = "";

    private FuncDataPermVo funcDataPermVo;

    private String funcCode;

    public String getFuncCode() {
        return funcCode;
    }

    public void setFuncCode(String funcCode) {
        this.funcCode = funcCode;
    }

    public FuncDataPermVo getFuncDataPermVo() {
        return funcDataPermVo;
    }

    public void setFuncDataPermVo(FuncDataPermVo funcDataPermVo) {
        this.funcDataPermVo = funcDataPermVo;
    }


    public boolean isOverrideFuncOrder() {
        return overrideFuncOrder;
    }

    public void setOverrideFuncOrder(boolean overrideFuncOrder) {
        this.overrideFuncOrder = overrideFuncOrder;
    }

    /**
     * 构建Query对象
     *
     * @param queryCollections 前端条件数组
     * @return com.je.core.mapper.query.Query
     */
    public static Query build(String queryCollections) {
        if (StringUtils.isNotBlank(queryCollections)) {
            try {
                JSONReader.Context context = new JSONReader.Context();
                context.setArraySupplier(()->new ArrayList());
                Query query = JSON.parseObject(queryCollections, Query.class,context);
                if (query == null) {
                    return new Query();
                }
                if (queryCollections.trim().startsWith("[") && (query.custom == null || query.custom.isEmpty())) {
                    List<Condition> custom = JSON.parseArray(queryCollections, Condition.class);
                    if (custom != null && custom.size() > 0) {
                        query.setCustom(custom);
                    }
                }
                query.setStrategyBean(null);
                query.setFuncOrderSql("");
                query.setFuncWhereSql("");
                query.setApplySql("");
                return query;
            } catch (JSONException e) {
                List<Condition> custom = JSON.parseArray(queryCollections, Condition.class);
                Query query = new Query();
                query.setCustom(custom);
                return query;
            }
        }
        return new Query();
    }

    /**
     * 构建Query对象
     *
     * @param queryCollections 前端条件数组
     * @return com.je.core.mapper.query.Query
     */
    public static Query buildWithObject(JSONObject queryCollections) {
        if (queryCollections != null) {
            try {
                JSONReader.Context context = new JSONReader.Context();
                context.setArraySupplier(()->new ArrayList());
                Query query = JSON.parseObject(queryCollections.toJSONString(),Query.class,context);
                query.setStrategyBean(null);
                query.setFuncOrderSql("");
                query.setFuncWhereSql("");
                query.setApplySql("");
                return query;
            } catch (JSONException e) {
                List<Condition> custom = JSON.parseArray(queryCollections.toJSONString(), Condition.class);
                Query query = new Query();
                query.setCustom(custom);
                return query;
            }
        }
        return new Query();
    }

    /**
     * 通过Query创建条件构造器，仅支持 custom
     *
     * @return com.je.ibatis.extension.conditions.ConditionsWrapper
     */
    public ConditionsWrapper buildWrapper() {
        return buildWrapper(ConditionsWrapper.builder());
    }

    /**
     * 通过Query修改条件构造器，仅支持 custom
     *
     * @param wrapper 条件构造器
     * @return com.je.ibatis.extension.conditions.ConditionsWrapper
     */
    public ConditionsWrapper buildWrapper(ConditionsWrapper wrapper) {
        if (wrapper == null) {
            wrapper = ConditionsWrapper.builder();
        }
        QueryBuilderService queryBuilder = SpringContextHolder.getBean(QueryBuilderService.class);
        wrapper.and(custom != null && !custom.isEmpty(), i -> {
            custom.forEach(p -> {
                queryBuilder.condition(i, p);
            });
        });
        //添加自定义sql
        wrapper.and(StringUtils.isNotBlank(applySql), i -> {
            i.apply(queryBuilder.trimSql(applySql));
        });
        return wrapper;
    }

    /**
     * 添加自定义条件
     *
     * @param code 字段
     * @return com.je.core.mapper.query.Query
     */
    public Query addOrder(String code) {
        return addOrder(code, "");
    }

    /**
     * 添加排序
     *
     * @param code 字段
     * @param type 条件类型
     * @return com.je.core.mapper.query.Query
     */
    public Query addOrder(String code, String type) {
        order.add(new Order(code, type));
        return this;
    }

    /**
     * 构建order语句，不包含 ORDER BY
     *
     * @return java.lang.String
     */
    public String buildOrder() {
        if (order != null && !order.isEmpty()) {
            StringBuffer orderBuffer = new StringBuffer();
            QueryBuilderService queryBuilder = SpringContextHolder.getBean(QueryBuilderService.class);
            order.forEach(p -> {
                orderBuffer.append(" ").append(queryBuilder.trimBlank(p.getCode())).append(" ").append(queryBuilder.trimBlank(p.getType())).append(",");
            });
            //删除末尾逗号
            orderBuffer.deleteCharAt(orderBuffer.length() - 1);
            return orderBuffer.toString();
        }
        return "";
    }

    /**
     * 添加自定义条件
     *
     * @param conditionJsonArray 条件数组
     * @return com.je.core.mapper.query.Query
     */
    public Query addCustoms(String conditionJsonArray) {
        List<Condition> conditions = JSON.parseArray(conditionJsonArray, Condition.class);
        custom.addAll(conditions);
        return this;
    }

    /**
     * 添加自定义条件
     *
     * @param code  字段
     * @param type  条件类型
     * @param value 值
     * @return com.je.core.mapper.query.Query
     */
    public Query addCustom(String code, ConditionEnum type, Object value) {
        return addCustom(code, type, value, null);
    }

    /**
     * 添加自定义条件
     *
     * @param code  字段
     * @param type  条件类型
     * @param value 值
     * @param cn    or或and
     * @return com.je.core.mapper.query.Query
     */
    public Query addCustom(String code, ConditionEnum type, Object value, String cn) {
        if (custom == null) {
            custom = new ArrayList<>();
        }
        custom.add(new Condition(code, type.getType(), value, cn));
        return this;
    }

    /**
     * 查找条件对象，仅支持 custom 一级查找
     *
     * @param code 字段名
     * @return com.je.core.mapper.query.Condition
     */
    public Condition findCondition(String code) {
        return findCondition(code, null);
    }

    /**
     * 查找条件对象，仅支持 custom 一级查找
     *
     * @param code  字段名
     * @param value 字段值，为null时不作为匹配条件
     * @return com.je.core.mapper.query.Condition
     */
    public Condition findCondition(String code, String value) {
        for (Condition c : custom) {
            boolean eq = code.equals(c.getCode()) && (value == null || value.equals(c.getValue()));
            if (eq) {
                return c;
            }
        }
        return null;
    }

    public String getSyProductId() {
        return syProductId;
    }

    public void setSyProductId(String syProductId) {
        this.syProductId = syProductId;
    }

    public String getAppId() {
        return appId;
    }

    public void setAppId(String appId) {
        this.appId = appId;
    }

    public JSONObject getAppFunc() {
        return appFunc;
    }

    public void setAppFunc(JSONObject appFunc) {
        this.appFunc = appFunc;
    }

    public String getApplySql() {
        return applySql;
    }

    public void setApplySql(String applySql) {
        this.applySql = applySql;
    }

    public List<Condition> getTree() {
        return tree;
    }

    public void setTree(List<Condition> tree) {
        this.tree = tree;
    }

    public List<Condition> getWorkflow() {
        return workflow;
    }

    public void setWorkflow(List<Condition> workflow) {
        this.workflow = workflow;
    }

    public List<Condition> getQuick() {
        return quick;
    }

    public void setQuick(List<Condition> quick) {
        this.quick = quick;
    }

    public FuncQueryStrategy getStrategyBean() {
        return strategyBean;
    }

    public void setStrategyBean(FuncQueryStrategy strategyBean) {
        this.strategyBean = strategyBean;
    }

    public List<Condition> getGroup() {
        return group;
    }

    public void setGroup(List<Condition> group) {
        this.group = group;
    }

    public List<Condition> getMark() {
        return mark;
    }

    public void setMark(List<Condition> mark) {
        this.mark = mark;
    }

    public List<Condition> getColumn() {
        return column;
    }

    public void setColumn(List<Condition> column) {
        this.column = column;
    }

    public List<Order> getOrder() {
        return order;
    }

    public void setOrder(List<Order> order) {
        this.order = order;
    }

    public String getFuncId() {
        return funcId;
    }

    public void setFuncId(String funcId) {
        this.funcId = funcId;
    }

    public String getFuncPkCode() {
        return funcPkCode;
    }

    public void setFuncPkCode(String funcPkCode) {
        this.funcPkCode = funcPkCode;
    }

    public boolean isOverrideFuncWhere() {
        return overrideFuncWhere;
    }

    public void setOverrideFuncWhere(boolean overrideFuncWhere) {
        this.overrideFuncWhere = overrideFuncWhere;
    }

    public String getFuncWhereSql() {
        return funcWhereSql;
    }

    public void setFuncWhereSql(String funcWhereSql) {
        this.funcWhereSql = funcWhereSql;
    }

    public String getFuncOrderSql() {
        return funcOrderSql;
    }

    public void setFuncOrderSql(String funcOrderSql) {
        this.funcOrderSql = funcOrderSql;
    }

    public String getStrategyId() {
        return strategyId;
    }

    public void setStrategyId(String strategyId) {
        this.strategyId = strategyId;
    }

    public List<Condition> getStrategy() {
        return strategy;
    }

    public void setStrategy(List<Condition> strategy) {
        this.strategy = strategy;
    }

    public JSONObject getFormData() {
        return formData;
    }

    public void setFormData(JSONObject formData) {
        this.formData = formData;
    }

    public List<Condition> getCustom() {
        return custom;
    }

    public void setCustom(List<Condition> custom) {
        this.custom = custom;
    }
}